#pragma once
#include<vector>
#include"../../instruction_module/operands.h"
#include<unordered_map>
#include"../../Global.h"
#include"../../hardware_resource/LDST_mode_enum.h"
#include"../../memory_module/memory_space.h"
#include <iostream>

//用于收集向量模块进行寄存器写入时，16个VPE的结果收集、同步和整合
typedef struct wri_r {
    uint64_t value;
    int reg_id;
    int delay;
} write_req_info_reg;

//父类用于在容器中承接不同类型的写入请求，统一简洁
class WriteReq {
public:
    virtual ~WriteReq() {}
    virtual bool write() {}
    virtual void print_info() {} //for debug

};

//SPU提交的局部向量写入请求
class WriteReq_SR : public WriteReq {
public:
    WriteReq_SR(int reg_id, uint64_t res_value, RegisterFile* rf)
                    : dst_reg_id(reg_id), reg_value(res_value), RF(rf) {

    }
    ~WriteReq_SR() {

    }
    //使用多态来简化代码
    bool write() override {
        std::cout << "Writing scalar register ID " << dst_reg_id << " with value " << reg_value << std::endl;
        return this->RF->set_register_value(this->dst_reg_id, this->reg_value);
    }

    void print_info() override {
        std::cout << "Scalar Register Write Request: ID = " << this->dst_reg_id << ", Value = " << this->reg_value << std::endl;
    }

private:
    int dst_reg_id;
    uint64_t reg_value;
    RegisterFile* RF;
};

//VPU提交的局部向量写入请求
class WriteReq_VR : public WriteReq {
public:
    WriteReq_VR(int reg_id, std::vector<uint64_t>* res_value, RegisterFile* rf)
                    : dst_reg_id(reg_id), reg_value(res_value), RF(rf) {

    }
    ~WriteReq_VR() {

    }
    //使用多态来简化代码
    bool write() override {
        return this->RF->set_register_value(this->dst_reg_id, this->reg_value);
    }

private:
    int dst_reg_id;
    std::vector<uint64_t>* reg_value;
    RegisterFile* RF;
};

//VPU提交的写入AM请求
class WriteReq_VLDST : public WriteReq {
public:
    WriteReq_VLDST(std::vector<uint64_t>* reg_value1, addr_size_t addr, int8_t mem_size, V_memory* am)
                   : value1(reg_value1), addr(addr), size(mem_size), AM(am)
    {}
    ~WriteReq_VLDST() {}
    bool write() override {
        //调用内存的向量接口来实现写入
        //TODO:跟路哥确认带模的load/store，具体是如何操作的，是否需要与DW额外不同的处理
        if (this->size == HW) {
            this->AM->store_hw_vector(this->addr, this->value1);
        } else {
            this->AM->store_w_vector(this->addr, this->value1);
        }
    }

private:
    std::vector<uint64_t>*  value1;
    addr_size_t addr; //存储的起始地址
    int8_t  size; //HW/W
    V_memory* AM;
};

//以下两个reg单独用于VLDST中的数据混洗操作
class WriteReq_VLDST_LDM : public WriteReq {
public:
    WriteReq_VLDST_LDM(int mod_num, RegisterFile* rf) : mod(mod_num), RF(rf) {}
    ~WriteReq_VLDST_LDM() {}
    void add_LDST0_info(std::vector<uint64_t>* value1, std::vector<uint64_t>* value2, int reg_id_1);
    void add_LDST1_info(std::vector<uint64_t>* value3, std::vector<uint64_t>* value4, int reg_id_2);
    bool write() override {
        //!!!ATTENTION:此处对vector的初始化操作，会使得vector先有16个0值，后续push_back操作会在后面继续添加值，最终vector大小会变为32
        //!!!后续需要把这些0值去掉，或者在初始化时直接使用reserve函数预留空间
        std::vector<uint64_t>* new_1 = new std::vector<uint64_t>();
        new_1->reserve(16);
        std::vector<uint64_t>* new_2 = new std::vector<uint64_t>();
        new_2->reserve(16);
        std::vector<uint64_t>* new_3 = new std::vector<uint64_t>();
        new_3->reserve(16);
        std::vector<uint64_t>* new_4 = new std::vector<uint64_t>();
        new_4->reserve(16);
        if (mod == 2) {
            for (int i = 0; i < 16; i++) {
                if (i % 2 == 0) {
                    new_1->push_back(value1->at(i));
                } else {
                    new_3->push_back(value1->at(i));
                }
            }
            for (int i = 0; i < 16; i++) {
                if (i % 2 == 0) {
                    new_1->push_back(value2->at(i));
                } else {
                    new_3->push_back(value2->at(i));
                }
            }
            for (int i = 0; i < 16; i++) {
                if (i % 2 == 0) {
                    new_2->push_back(value3->at(i));
                } else {
                    new_4->push_back(value3->at(i));
                }
            }
            for (int i = 0; i < 16; i++) {
                if (i % 2 == 0) {
                    new_2->push_back(value4->at(i));
                } else {
                    new_4->push_back(value4->at(i));
                }
            }
        } else if (mod == 4) {
            for (int i = 0; i < 16; i = i + 4) {
                new_1->push_back(value1->at(i));
                new_2->push_back(value1->at(i + 1));
                new_3->push_back(value1->at(i + 2));
                new_4->push_back(value1->at(i + 3));
            }
            for (int i = 0; i < 16; i = i + 4) {
                new_1->push_back(value2->at(i));
                new_2->push_back(value2->at(i + 1));
                new_3->push_back(value2->at(i + 2));
                new_4->push_back(value2->at(i + 3));
            }
            for (int i = 0; i < 16; i = i + 4) {
                new_1->push_back(value3->at(i));
                new_2->push_back(value3->at(i + 1));
                new_3->push_back(value3->at(i + 2));
                new_4->push_back(value3->at(i + 3));
            }
            for (int i = 0; i < 16; i = i + 4) {
                new_1->push_back(value4->at(i));
                new_2->push_back(value4->at(i + 1));
                new_3->push_back(value4->at(i + 2));
                new_4->push_back(value4->at(i + 3));
            }
        } else {
            std::cout << "in WriteReq_VLDST_LDM : WRONG MOD NUMBER!!!" << std::endl;
        }
        delete value1;
        delete value2;
        delete value3;
        delete value4;
        this->RF->set_register_value(dst_reg_1, new_1);
        this->RF->set_register_value(dst_reg_1 + 1, new_2);
        this->RF->set_register_value(dst_reg_2, new_3);
        this->RF->set_register_value(dst_reg_2 + 1, new_4);
    }

private:
    //for ldst0
    std::vector<uint64_t>*    value1;
    std::vector<uint64_t>*    value2;
    //for ldst1
    std::vector<uint64_t>*    value3;
    std::vector<uint64_t>*    value4;
    //!混洗操作需要两条指令放在一起重排数据后再进行操作
    int mod; //存储该条指令进行模几操作
    int dst_reg_1; //存储LDDDW0Mx的目的寄存器
    int dst_reg_2; //存储LDDDW1Mx的目的寄存器
    RegisterFile* RF;
};

class WriteReq_VLDST_STM : public WriteReq {
public:
    WriteReq_VLDST_STM(int mod_num, V_memory* am) : mod(mod_num), AM(am) {}
    ~WriteReq_VLDST_STM() {}
    void add_LDST0_info(std::vector<uint64_t>* value1, std::vector<uint64_t>* value2, addr_size_t addr1);
    void add_LDST1_info(std::vector<uint64_t>* value3, std::vector<uint64_t>* value4, addr_size_t addr2);
    bool write() override {
        //!!!ATTENTION:此处对vector的初始化操作，会使得vector先有16个0值，后续push_back操作会在后面继续添加值，最终vector大小会变为32
        //!!!后续需要把这些0值去掉，或者在初始化时直接使用reserve函数预留空间
        std::vector<uint64_t>* new_1 = new std::vector<uint64_t>();
        new_1->reserve(16);
        std::vector<uint64_t>* new_2 = new std::vector<uint64_t>();
        new_2->reserve(16);
        std::vector<uint64_t>* new_3 = new std::vector<uint64_t>();
        new_3->reserve(16);
        std::vector<uint64_t>* new_4 = new std::vector<uint64_t>();
        new_4->reserve(16);
        if (mod == 16) {
            for (int i = 0; i < 4; i++) {
                new_1->push_back(value1->at(i));
                new_1->push_back(value2->at(i));
                new_1->push_back(value3->at(i));
                new_1->push_back(value4->at(i));
            }
            for (int i = 4; i < 8; i++) {
                new_2->push_back(value1->at(i));
                new_2->push_back(value2->at(i));
                new_2->push_back(value3->at(i));
                new_2->push_back(value4->at(i));
            }
            for (int i = 8; i < 12; i++) {
                new_3->push_back(value1->at(i));
                new_3->push_back(value2->at(i));
                new_3->push_back(value3->at(i));
                new_3->push_back(value4->at(i));
            }
            for (int i = 12; i < 16; i++) {
                new_4->push_back(value1->at(i));
                new_4->push_back(value2->at(i));
                new_4->push_back(value3->at(i));
                new_4->push_back(value4->at(i));
            }
        } else if (mod == 32) {
            for (int i = 0; i < 8; i++) {
                new_1->push_back(value1->at(i));
                new_1->push_back(value3->at(i));
                new_3->push_back(value2->at(i));
                new_3->push_back(value4->at(i));
            }
            for (int i = 8; i < 16; i++) {
                new_2->push_back(value1->at(i));
                new_2->push_back(value3->at(i));
                new_4->push_back(value2->at(i));
                new_4->push_back(value4->at(i));
            }
        } else {
            std::cout << "in WriteReq_VLDST_STM : WRONG MOD NUMBER!!!" << std::endl;
        }
        delete value1;
        delete value2;
        delete value3;
        delete value4;
        this->AM->store_w_vector(addr_1, new_1);
        this->AM->store_w_vector(addr_1 + 128, new_2);
        this->AM->store_w_vector(addr_2, new_3);
        this->AM->store_w_vector(addr_2 + 128, new_4);
    }

private:
    //for ldst0
    std::vector<uint64_t>*    value1;
    std::vector<uint64_t>*    value2;
    //for ldst1
    std::vector<uint64_t>*    value3;
    std::vector<uint64_t>*    value4;
    //!混洗操作需要两条指令放在一起重排数据后再进行操作
    int mod; //存储该条指令进行模几操作
    addr_size_t addr_1; //存储DW0Mx的起始地址
    addr_size_t addr_2; //存储DW1Mx的起始地址
    V_memory* AM;
};

//SPU提交的写入SM请求
class WriteReq_SLDST : public WriteReq {
public:
    WriteReq_SLDST(uint64_t reg_value1, addr_size_t addr, int8_t mem_size, memory* sm)
                   : value1(reg_value1), addr(addr), size(mem_size), SM(sm)
    {}
    ~WriteReq_SLDST() {}
    bool write() override {
        //调用内存的标量接口来实现写入
        if (size == HW) {
            uint64_t temp;
            std::memcpy(&temp, &(this->value1), sizeof(temp));
            uint32_t res = temp & 0xFFFFFFFF;
            this->SM->store_4_bytes(this->addr, res);
        } else if (size == W) {
            uint64_t temp;
            std::memcpy(&temp, &(this->value1), sizeof(temp));
            this->SM->store_8_bytes(this->addr, temp);
        } else if (size == B) {
            uint64_t temp;
            std::memcpy(&temp, &(this->value1), sizeof(temp));
            uint8_t res = temp & 0xFF;
            this->SM->store_1_byte(this->addr, res);
        } else if (size == DB) {
            uint64_t temp;
            std::memcpy(&temp, &(this->value1), sizeof(temp));
            uint16_t res = temp & 0xFFFF;
            this->SM->store_2_bytes(this->addr, res);
        }
        else {
            std::cout << "in WriteReq_SLDST : WRONG ACCESS SIZE!!!" << std::endl;
        }
    }

private:
    uint64_t  value1;
    addr_size_t addr; //存储的起始地址
    int8_t  size; //HW/W
    memory* SM;
};

class ControlSlot {
public:
    ControlSlot() {
        buckets = new std::unordered_map< global_clock_t, std::vector<WriteReq*> >();
        next_ptr = nullptr;
    }
    ~ControlSlot() {
        delete buckets;
        // delete next_ptr;
    }
    void set_next_ptr(ControlSlot* ptr);
    ControlSlot*    get_next_ptr();
    void write_and_clear();
    void set_buckets(WriteReq* wr);
    //true->load, false->store
    WriteReq*   merge_req(bool ldst);

private:
    //key是写入请求被提交时的global clock，value是同一时刻，被提交的所有请求序列
    std::unordered_map< global_clock_t, std::vector<WriteReq*> >*  buckets; 
    ControlSlot* next_ptr;
};

class WriteControlModule {
public:
    // WriteControlModule(V_memory* am, memory* sm, memory* gsm, RegisterFile* rf)
    //                     :AM(am), SM(sm), GSM(gsm), RF(rf) {
    //     //指令的延迟周期目前为1～9个周期，故总共需要9个slot来存储
    //     this->head_pointer = new ControlSlot();
    //     ControlSlot* temp_pointer = new ControlSlot();
    //     this->head_pointer->set_next_ptr(temp_pointer);
    //     for (int i = 0; i < 7; i++) {
    //         temp_pointer->set_next_ptr(new ControlSlot());
    //         temp_pointer = temp_pointer->get_next_ptr();
    //     }
    //     //将最后一个节点连接回头节点，形成环形链表
    //     temp_pointer->set_next_ptr(this->head_pointer);
    // }
    WriteControlModule(V_memory* am, memory* sm, memory* gsm, RegisterFile* rf)
                        :AM(am), SM(sm), GSM(gsm), RF(rf) {
        //指令的延迟周期目前为1～9个周期，故总共需要9个slot来存储
        this->head_pointer = new ControlSlot();
        ControlSlot* prev = this->head_pointer;
        for (int i = 1; i < 9; ++i) {
            ControlSlot* node = new ControlSlot();
            prev->set_next_ptr(node);
            prev = node;
        }
        prev->set_next_ptr(this->head_pointer); // 最后一个节点指向头节点，形成环
    }
    
    ~WriteControlModule() {
        //TODO：将创建的slot环形链表delete掉
        ControlSlot* temp_pointer = this->head_pointer->get_next_ptr();
        //!ATTENTION:调试时若出现bug，考虑该处可能出现的指针问题
        for (int i = 0; i < 9; i++) {
            delete this->head_pointer;
            this->head_pointer = temp_pointer;
            temp_pointer = this->head_pointer->get_next_ptr();
        }
    }
    void do_the_real_thing();
    //局部向量寄存器写入请求提交APIs
    void post_write_req(int reg_id, std::vector<uint64_t>* value, int delay);
    void post_write_req(int reg_id, uint64_t value, int delay);
    //局部内存(AM, SM)写入请求提交APIs
    void post_write_req(addr_size_t addr, std::vector<uint64_t>* value1, int8_t access_size, int delay);
    void post_write_req(addr_size_t addr, uint64_t value1, int8_t access_size, int delay);
    //VLDST中出现混洗指令时进行提交请求的APIs
    //访存粒度均为双字DW
    //true->vldst0, false->vldst1
    void post_write_req_m(int reg_id, std::vector<uint64_t>* value1, std::vector<uint64_t>* value2, int mod_num, bool zero_one, int delay);
    void post_write_req_m(addr_size_t addr, std::vector<uint64_t>* value1, std::vector<uint64_t>* value2, int mod_num, bool zero_one, int delay);

private:
    V_memory* AM;
    memory* SM;
    memory* GSM;
    RegisterFile* RF;
    ControlSlot*    head_pointer;
};